from puremvc.core import Controller
from puremvc.core import Model
from puremvc.core import View
from puremvc.patterns.observer import Notification


class Facade(object):
    def __new__(cls, *args, **kwargs):
        # Implementation #1: It guarantees that each get_instance() of Facade
        # or its subclasses' gets a singleton of THAT class. In other words,
        # each Facade and its subclass will at most have one independent
        # singleton instance.
        if not hasattr(cls, '_instance') or type(cls._instance) != cls:
            cls._instance = super(Facade, cls).__new__(cls, *args, **kwargs)
            cls._instance._init_facade()

        return cls._instance

        """
        # Implementation #2: Similar to #1, but if parent class's
        # get_instance() is called first, a child class's get_instance will
        # only return the same instance.
        if not hasattr(cls, '_instance') or isinstance(cls._instance, cls):
            cls._instance = super(Facade, cls).__new__(cls, *args, **kwargs)
            cls._instance._init_facade()

        return cls._instance

        # Implementation #3: All Facade and its subclasses can only have ONE
        # singleton instance.
        if not hasattr(Facade, '_instance'):
            Facade._instance = super(Facade, cls).__new__(cls, *args, **kargs)
            Facade._instance._init_facade()

        return Facade._instance
        """

    def _init_facade(self):
        self._init_controller()
        self._init_model()
        self._init_view()

    def _init_controller(self):
        if not hasattr(self, '_controller'):
            self._controller = Controller.getInstance()
        else:
            return

    def _init_model(self):
        if not hasattr(self, '_model'):
            self._model = Model.getInstance()
        else:
            return

    def _init_view(self):
        if not hasattr(self, '_view'):
            self._view = View.getInstance()
        else:
            return

    @staticmethod
    def get_instance():
        return Facade()

    def register_cmd(self, notification_name, cmd_class_ref):
        self._controller.registerCommand(notification_name, cmd_class_ref)

    def remove_cmd(self, notification_name):
        self._controller.removeCommand(notification_name)

    def has_cmd(self, notification_name):
        return self._controller.hasCommand(notification_name)

    def register_proxy(self, proxy):
        self._model.registerProxy(proxy)

    def retrieve_proxy(self, proxy_name):
        return self._model.retrieveProxy(proxy_name)

    def has_proxy(self, proxy_name):
        return self._model.hasProxy(proxy_name)

    def register_mediator(self, mediator):
        self._view.registerMediator(mediator)

    def retrieve_mediator(self, mediator_name):
        return self._view.retrieveMediator(mediator_name)

    def remove_mediator(self, mediator_name):
        return self._view.removeMediator(mediator_name)

    def has_mediator(self, mediator_name):
        return self._view.hasMediator(mediator_name)

    def send_notification(self, notification_name, body=None, type=None):
        self.notify_observers(Notification(notification_name, body, type))

    def notify_observers(self, notification):
        self._view.notifyObservers(notification)
